/***************************************************************************
 *                                                                         *
 * Copyright (c) 2007 - 2009 Nuvoton Technology Corp. All rights reserved.*
 *                                                                         *
 ***************************************************************************/
 
 
#ifdef ECOS
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "drv_api.h"
#include "diag.h"
#include "wbio.h"
#include "NUC900_GE.h"
#include "NUC900_GE_Regs.h"
#include "NUC900_reg.h"
#else
#include <stdio.h>
#include "NUC900_GE.h"
#include "NUC900_GE_Regs.h"
#include "wbio.h"
#ifdef _NUC900_
#include "NUC900_reg.h"
#else
#include "reg702.h"
#endif
#endif

/*

The W99702 hardware has some limitation on the Host Read/Write BLT. 
The mono source will be handled by hardware.

Software must be care of the adding of one pseudo data port read/write at
end of a line according to the BPP, start X and transfer width.

Maybe the hardware will fix it in next version.

*/

/*
** This function is used to check if the pseudo read/write
** is necessary or not.
**
** Hardware will send the dummy read/write automatically according
** to the rule. Thus, software doesn't need to take care.
*/
int check_pseudo_RW(int bpp, int sx, int width)
{
  int pseudo_RW;
  int budget, demand;
  int start_index; // in first FIFO
  int stop_index;
  int trans_len;
   
  budget = (width*(GFX_BPP/8)+3)>>2; // in DWORD count
  trans_len = width * (GFX_BPP/8);
   
  if (bpp==8)
  {
    start_index = sx % 4;
    stop_index = start_index + trans_len - 1;
    demand = 1 + (stop_index>>2); // how may FIFO needed for transfer?
    pseudo_RW = demand - budget;
  }
  else if (bpp==16)
  {
    start_index = (sx % 2) * 2;
    stop_index = start_index + trans_len - 1;
    demand = 1 + (stop_index>>2);
    pseudo_RW = demand - budget;
  }
  else pseudo_RW = 0;
  
  if (pseudo_RW > 1)
  {
    while (1); 
  }

#ifdef DEBUG  
  printf("demand=%d budget=%d\n", demand, budget);
#endif   

  return pseudo_RW;
}
  


///////////////////////////////////////////////////////////////////////////////
//
// Function: host_write_blt()
//
// Description:
//   Host-to-Screen BitBlt with SRCCOPY (through data port). 
//
///////////////////////////////////////////////////////////////////////////////
/*
** Host Write BLT through data port. 
** To make the transfer efficient, the start address and stride
** must be multiple of 4.
*/
void host_write_blt(int x, int y, int width, int height, void *buf)
{
  UINT32 cmd32, dest_pitch, dest_start, dest_dimension;
  int transfer_count, i, j;
  UINT32 *ptr32, data32;
#ifdef USE_PSEUDO_WRITE  
  int pseudo_write;
#endif  

#ifdef DEBUG   
  printf("host_write_blt()\n");
  printf("(%d,%d)-(%d,%d)\n", x, y, x+width-1, y+height-1);
  printf("width=%d height=%d\n", width, height);
#endif 
 
  cmd32 = 0xcc430020; 
  
  outpw(REG_2D_GEC, cmd32);

  dest_pitch = GFX_WIDTH << 16; // pitch in pixel
  outpw(REG_2D_GESDP, dest_pitch);
  
  dest_start = y << 16 | x;
  outpw(REG_2D_GEDSXYL, dest_start);
  
  dest_dimension = height << 16 | width;
  outpw(REG_2D_GEDIXYL, dest_dimension);  

#ifdef USE_PSEUDO_WRITE
  pseudo_write = check_pseudo_RW(GFX_BPP, x, width);
#endif
  
  outpw(REG_2D_GETG, 1); 

  ptr32 = (UINT32 *)buf;
  for (i=0; i<height; i++)   // 120
  {
    //printf("line %d\n", i);
    transfer_count = (width * (GFX_BPP/8) + 3) / 4; // 4-byte count
  
    while (transfer_count >= 8)
    {
      while ((inpw(REG_2D_GEMC) & 0x00000800)==0); // check empty
      for (j=0; j<8; j++) 
      {
        data32 = *ptr32++;
        outpw(REG_2D_GEHBDW0, data32);
      }
      transfer_count -= 8;
    }
    
    if (transfer_count > 0)
    {
      while ((inpw(REG_2D_GEMC) & 0x00000800)==0); // check empty
      for (j=0; j<transfer_count; j++) 
      {
        data32 = *ptr32++;
        outpw(REG_2D_GEHBDW0, data32);
      } 
    }
    
#ifdef USE_PSEUDO_WRITE
    if (pseudo_write==1) 
    {
      outpw(REG_2D_GEHBDW0, 0);
    }
#endif    
  }
 
  while ((inpw(REG_2D_GEINTS)&0x01)==0); // wait for command complete  

  outpw(REG_2D_GEINTS, 1); // clear interrupt status
}


///////////////////////////////////////////////////////////////////////////////
//
// Function: host_read_blt()
//
// Description:
//   Screen-to-Host BitBlt with SRCCOPY (through data port).
//
//   Hardware can handle pseudo READ. 
//
///////////////////////////////////////////////////////////////////////////////
void host_read_blt(int x, int y, int width, int height, void *buf)
{
  UINT32 cmd32, dest_pitch, dest_start, dest_dimension;
  int transfer_count, i, j;
  UINT32 *ptr32;

#ifdef DEBUG   
  printf("host_read_blt()\n");
  printf("(%d,%d)-(%d,%d)\n", x, y, x+width-1, y+height-1);
  printf("width=%d height=%d\n", width, height);  
#endif 
 
  cmd32 = 0xcc430001; 
  
  outpw(REG_2D_GEC, cmd32);

  dest_pitch = GFX_WIDTH << 16; // pitch in pixel
  outpw(REG_2D_GESDP, dest_pitch);
  
  dest_start = y << 16 | x;
  outpw(REG_2D_GEDSXYL, dest_start);
  
  dest_dimension = height << 16 | width;
  outpw(REG_2D_GEDIXYL, dest_dimension);  
  
  outpw(REG_2D_GETG, 1); 

  ptr32 = (UINT32 *)buf;
  for (i=0; i<height; i++)
  {
    //printf("<%d>\n", i);
    transfer_count = (width * (GFX_BPP/8) + 3) / 4; // 4-byte count
    
    while (transfer_count >= 8)
    {
      while ((inpw(REG_2D_GEMC) & 0x00000400)==0);
      for (j=0; j<8; j++) 
      {
        *ptr32++ = inpw(REG_2D_GEHBDW0);
      }
      transfer_count -= 8;
    }
    
    if (transfer_count > 0)
    {
      while (((inpw(REG_2D_GEMC) & 0x0000f000)>>12) != transfer_count);
      for (j=0; j<transfer_count; j++) 
      {
        *ptr32++ = inpw(REG_2D_GEHBDW0);
      } 
    }   
  }
  
  while ((inpw(REG_2D_GEINTS)&0x01)==0); // wait for command complete  

  outpw(REG_2D_GEINTS, 1); // clear interrupt status
}


///////////////////////////////////////////////////////////////////////////////
//
// Function: host_sprite_blt()
//
// Description:
//   Host-to-Screen SpriteBlt with SRCCOPY. 
//
///////////////////////////////////////////////////////////////////////////////
void host_sprite_blt(int x, int y, int width, int height, void *buf)
{
  UINT32 cmd32, dest_pitch, dest_start, dest_dimension;
  int transfer_count, i, j;
  UINT32 *ptr32, data32, alpha;

#ifdef DEBUG   
  printf("host_sprite_blt()\n");
  printf("(%d,%d)-(%d,%d)\n", x, y, x+width-1, y+height-1);
#endif 

  cmd32 = 0xcc430020; 
  
  outpw(REG_2D_GEC, cmd32);

  dest_pitch = GFX_WIDTH << 16; // pitch in pixel
  outpw(REG_2D_GESDP, dest_pitch);
  
  dest_start = y << 16 | x;
  outpw(REG_2D_GEDSXYL, dest_start);
  
  dest_dimension = height << 16 | width;
  outpw(REG_2D_GEDIXYL, dest_dimension);  

  if (_ClipEnable)
  {
    cmd32 |= 0x00000200;
    if (_OutsideClip)
    {
      cmd32 |= 0x00000100;
    }
    outpw(REG_2D_GEC, cmd32);
    outpw(REG_2D_GECBTL, _ClipTL);
    outpw(REG_2D_GECBBR, _ClipBR);
  }  

  if (_DrawMode==MODE_TRANSPARENT)
  {
    cmd32 |= 0x00008000; // color transparency 
    outpw(REG_2D_GEC, cmd32);
    outpw(REG_2D_GETC, _ColorKey);
    outpw(REG_2D_GETCM, _ColorKeyMask);
  }  
  else if (_DrawMode==MODE_DEST_TRANSPARENT)
  {
    cmd32 |= 0x00009000;
    outpw(REG_2D_GEC, cmd32);
    outpw(REG_2D_GETC, _ColorKey);
    outpw(REG_2D_GETCM, _ColorKeyMask);
  }
  
  if (_EnableAlpha)
  {
    cmd32 |= 0x00200000;
    outpw(REG_2D_GEC, cmd32);
    
    data32 = inpw(REG_2D_GEMC) & 0x0000ffff;
    alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd);
    data32 |= (alpha << 16);
    
    outpw(REG_2D_GEMC, data32);
  }  
  
  outpw(REG_2D_GETG, 1); 

  ptr32 = (UINT32 *)buf;
  for (i=0; i<height; i++)
  {
    transfer_count = width * (GFX_BPP/8) / 4; // 4-byte count
  
    while (transfer_count > 8)
    {
      while ((inpw(REG_2D_GEMC) & 0x00000800)==0); // check empty
      for (j=0; j<8; j++) 
      {
        data32 = *ptr32++;
        outpw(REG_2D_GEHBDW0, data32);
      }
      transfer_count -= 8;
    }
    
    if (transfer_count > 0)
    {
      while ((inpw(REG_2D_GEMC) & 0x00000800)==0); // check empty
      for (j=0; j<transfer_count; j++) 
      {
        data32 = *ptr32++;
        outpw(REG_2D_GEHBDW0, data32);
      } 
    }   
  }
 
  while ((inpw(REG_2D_GEINTS)&0x01)==0); // wait for command complete  

  outpw(REG_2D_GEINTS, 1); // clear interrupt status
}


